
// table containing list of hotkeys
MuseX.HotKeyList = {};
	
// default hotkey think
MuseX.NextHotKeyThink = 0;

// editing information
MuseX.Editing = nil;


/*------------------------------------
	initialize hotkeys
------------------------------------*/
function MuseX.InitHotKeys( defaults )

	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_open", "open", function() MuseX.ToggleVGUI(); end, "MCTRLSHIFT" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_playpause", "playpayse", function() MuseX.PlayPause(); end, "PCTRL" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_mute", "mute", function() MuseX.ToggleMute(); end, "MCTRL" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_previous", "previous", function() MuseX.PreviousSong( true ); end, "[LEFT]CTRL" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_next", "next", function() MuseX.NextSong( true ); end, "[RIGHT]CTRL" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_volumeup", "volup", function() MuseX.ChangeVolume( 0.1, true ); end, "[UP]CTRL" );
	
	// define
	MuseX.DefineHotKey( "#musex_hotkeys_key_volumedown", "voldn", function() MuseX.ChangeVolume( -0.1, true ); end, "[DOWN]CTRL" );

end


/*------------------------------------
	restore hotkey defaults
------------------------------------*/
function MuseX.DefaultHotKeys( )

	// empty table
	local defaults = {};

	// loop through list of hotkeys
	for _, data in pairs( MuseX.HotKeyList ) do
	
		// rebuild the default stroke
		defaults[ data.Default ] = table.Copy( data );
		
		// update the setting
		MuseX.SetSetting( ("HOTKEY_%s"):format( data.Key ), data.Default );
	
	end
	
	// update list
	MuseX.HotKeyList = defaults;
	
end


/*------------------------------------
	define a new hotkey
------------------------------------*/
function MuseX.DefineHotKey( name, key, func, stroke )

	// store the hotkey information
	MuseX.HotKeyList[ MuseX.GetSetting( ("HOTKEY_%s"):format( key ) ) or stroke ] = {
	
		// store the name
		[ 'Name' ] = name,
		
		// store the key
		[ 'Key' ] = key,
		
		// store the function
		[ 'Func' ] = func,
		
		// default
		[ 'Default' ] = stroke,
	
	};

end


/*------------------------------------
	main hotkey think routine
------------------------------------*/
function MuseX.HotKeysThink( )

	// make sure its time to think
	if ( MuseX.NextHotKeyThink > MXCurTime() ) then
	
		// too early
		return;
	
	end
	
	// set the new think time
	MuseX.NextHotKeyThink = MXCurTime() + 0.05;
	
	// key integer to string translation
	// FIXME: is this really necessary? is there another
	// way to do it more effectively?
	local keytable = {
		[ KEY_COMMA ] = ",",
		[ KEY_PERIOD ] = ".",
		[ KEY_SLASH ] = "/",
		[ KEY_SPACE ] = "[SP]",
		[ KEY_SEMICOLON ] = ";",
		[ KEY_APOSTROPHE ] = "'",
		[ KEY_LBRACKET ] = "[",
		[ KEY_RBRACKET ] = "]",
		[ KEY_BACKSLASH ] = "\\",
		[ KEY_INSERT ] = "[INS]",
		[ KEY_DELETE ] = "[DEL]",
		[ KEY_HOME ] = "[HOME]",
		[ KEY_END ] = "[END]",
		[ KEY_PAGEUP ] = "[PGUP]",
		[ KEY_PAGEDOWN ] = "[PGDN]",
		[ KEY_MINUS ] = "-",
		[ KEY_EQUAL ] = "=",
		[ KEY_LEFT ] = "[LEFT]",
		[ KEY_RIGHT ] = "[RIGHT]",
		[ KEY_UP ] = "[UP]",
		[ KEY_DOWN ] = "[DOWN]",
		[ KEY_0 ] = "0",
		[ KEY_1 ] = "1",
		[ KEY_2 ] = "2",
		[ KEY_3 ] = "3",
		[ KEY_4 ] = "4",
		[ KEY_5 ] = "5",
		[ KEY_6 ] = "6",
		[ KEY_7 ] = "7",
		[ KEY_8 ] = "8",
		[ KEY_9 ] = "9",
		[ KEY_A ] = "A",
		[ KEY_B ] = "B",
		[ KEY_C ] = "C",
		[ KEY_D ] = "D",
		[ KEY_E ] = "E",
		[ KEY_F ] = "F",
		[ KEY_G ] = "G",
		[ KEY_H ] = "H",
		[ KEY_I ] = "I",
		[ KEY_J ] = "J",
		[ KEY_K ] = "K",
		[ KEY_L ] = "L",
		[ KEY_M ] = "M",
		[ KEY_N ] = "N",
		[ KEY_O ] = "O",
		[ KEY_P ] = "P",
		[ KEY_Q ] = "Q",
		[ KEY_R ] = "R",
		[ KEY_S ] = "S",
		[ KEY_T ] = "T",
		[ KEY_U ] = "U",
		[ KEY_V ] = "V",
		[ KEY_W ] = "W",
		[ KEY_X ] = "X",
		[ KEY_Y ] = "Y",
		[ KEY_Z ] = "Z"
	};
	
	// get the stroke information
	local ctrl = ( input.IsKeyDown( KEY_LCONTROL ) || input.IsKeyDown( KEY_RCONTROL ) ) && "CTRL" || "";
	local alt = ( input.IsKeyDown( KEY_LALT ) || input.IsKeyDown( KEY_RALT ) ) && "ALT" || "";
	local shift = ( input.IsKeyDown( KEY_LSHIFT ) || input.IsKeyDown( KEY_RSHIFT ) ) && "SHIFT" || "";
	
	// loop through possible keys
	for i, key in pairs( keytable ) do

		// check if the key is down
		if ( input.IsKeyDown( i ) ) then
			
			// build the stroke string
			local stroke = ("%s%s%s%s"):format( key, ctrl, alt, shift );
			
			// make sure its a complex enough stroke to be considered a hotkey
			if ( #stroke > 2 ) then
			
				// check if we're editing keys
				if ( MuseX.Editing ) then
				
					// finish the edit process
					MuseX.FinishEditHotKey( stroke );
					
					// done here
					return;
				
				else
			
					// check if the hotkey exists
					if ( MuseX.HotKeyList[ stroke ] ) then
						
						// call the associated function
						MuseX.HotKeyList[ stroke ].Func();
						
					end
					
				end
				
				// delay the next hotkey use
				MuseX.NextHotKeyThink = MXCurTime() + 0.2;
			
			end
			
			// exit the loop
			break;
		
		end
	
	end

end


/*------------------------------------
	begin process for editing hotkey
------------------------------------*/
function MuseX.StartEditHotKey( name, out, old )

	// check if we're already editing
	if ( MuseX.Editing ) then
	
		// cancel the old keystroke edit
		MuseX.Editing.Output:ShowStroke( MuseX.Editing.Old );
	
	end
	
	// store the new editing information
	MuseX.Editing = {
	
		[ 'Name' ] = name,
		[ 'Output' ] = out,
		[ 'Old' ] = old
		
	};
	
	// update the text
	out:SetText( "press a keystroke..." );
	
end


/*------------------------------------
	finish the hotkey edit process
------------------------------------*/
function MuseX.FinishEditHotKey( stroke )

	// if we're not editing leave
	if ( !MuseX.Editing ) then
	
		// leave?
		return;
		
	end
	
	// check to make sure we're not setting a duplicate keystroke
	if( MuseX.HotKeyList[ stroke ] && MuseX.HotKeyList[ stroke ][ 'Name' ] != MuseX.Editing.Name ) then
	
		// let them know they are an idiot
		MuseX.Editing.Output:SetText( "duplicate key, try again..." );
		
		// done
		return;
		
	end
	
	// check if a stroke was supplied
	if ( stroke ) then
	
		// update the text
		MuseX.Editing.Output:ShowStroke( stroke );
		
		// loop through list of hotkeys
		for s, data in pairs( MuseX.HotKeyList ) do
		
			// match the editing name
			if ( MuseX.Editing.Name == data.Name ) then
			
				// move the keystroke information
				MuseX.HotKeyList[ stroke ] = table.Copy( data );
				
				// check if they pressed the same keystroke
				if ( s != stroke ) then
				
					// remove the old one
					MuseX.HotKeyList[ s ] = nil;
					
				end
				
				// update the setting
				MuseX.SetSetting( ("HOTKEY_%s"):format( MuseX.HotKeyList[ stroke ][ 'Key' ] ), stroke );
				
				// exit loop
				break;
			
			end
		
		end
		
	end

	// clear editing information
	MuseX.Editing = nil;

end
